/**
 * 生成缩略图
 * 支持图片，视频，iframe等dom元素，输出指定宽高的png图片
 */

import { snapdom } from "@zumer/snapdom";
import domtoimage from "dom-to-image-more";
import html2canvas from "html2canvas";
import * as htmlToImage from "html-to-image";

/**
 * 生成缩略图的配置选项
 */
export interface ThumbnailOptions {
  /** 缩略图宽度 */
  width: number;
  /** 缩略图高度 */
  height: number;
  /** 缩放比例 */
  scale?: number;
  /** 图片质量 (0-1) */
  quality?: number;
}

/**
 * 生成DOM元素的缩略图
 * @param element 要生成缩略图的DOM元素
 * @param options 缩略图配置选项
 * @returns Promise<HTMLImageElement> 生成的缩略图图片元素
 */
/**
 * 生成DOM元素的缩略图（使用snapdom库）
 * @param element 要生成缩略图的DOM元素
 * @param options 缩略图配置选项
 * @returns Promise<HTMLImageElement> 生成的缩略图图片元素
 */
export async function generateThumbnail(
  element: HTMLElement,
  options: ThumbnailOptions
): Promise<HTMLImageElement> {
  try {
    // 从选项中提取参数，设置默认值
    const { width, height, scale = 1, quality = 0.9 } = options;

    // 检查元素是否存在
    if (!element) {
      throw new Error("DOM元素不存在");
    }

    // 确保所有资源（图片、视频等）都已加载完成
    await ensureAllResourcesLoaded(element);

    // 克隆原始元素，避免修改原始DOM
    const clonedElement = element.cloneNode(true) as HTMLElement;
    
    // 临时保存原始样式，以便后续恢复
    const originalStyle = {
      width: clonedElement.style.width,
      height: clonedElement.style.height,
      position: clonedElement.style.position,
      top: clonedElement.style.top,
      left: clonedElement.style.left,
      opacity: clonedElement.style.opacity,
      zIndex: clonedElement.style.zIndex
    };

    // 设置克隆元素的样式使其不可见但可以被渲染
    clonedElement.style.width = `${width / scale}px`;
    clonedElement.style.height = `${height / scale}px`;
    clonedElement.style.position = "absolute";
    clonedElement.style.top = '-9999px';
    clonedElement.style.left = '-9999px';
    clonedElement.style.zIndex = '-1';
    
    // 对于snapdom，元素不能是完全透明的，所以设置一个极低的透明度
    // clonedElement.style.opacity = "0.01";

    // 将克隆元素添加到文档中以便渲染
    document.body.appendChild(clonedElement);
    
    // 等待一帧确保元素已渲染
    await new Promise(resolve => requestAnimationFrame(resolve));

    // 处理克隆元素中的特殊元素（canvas、video等）
    await processSpecialElements(clonedElement, element);
    
    // 再次等待一帧确保特殊元素处理完成
    await new Promise(resolve => requestAnimationFrame(resolve));

    // 使用snapdom生成PNG图片
    let pngImage;
    try {
      pngImage = await snapdom.toPng(clonedElement, { quality });
    } catch (snapError) {
      console.warn('snapdom直接截图失败，尝试使用备用方法:', snapError);
      // 如果直接截图失败，尝试将元素添加到视口内短暂截图
      clonedElement.style.top = '0px';
      clonedElement.style.left = '0px';
      clonedElement.style.opacity = '0.01';
      clonedElement.style.pointerEvents = 'none';
      
      // 等待元素位置更新
      await new Promise(resolve => setTimeout(resolve, 50));
      
      // 再次尝试截图
      pngImage = await snapdom.toPng(clonedElement, { quality });
    }

    // 恢复克隆元素的原始样式并从文档中移除
    Object.assign(clonedElement.style, originalStyle);
    
    // 立即移除克隆元素，不需要延迟
    try {
      document.body.removeChild(clonedElement);
    } catch (removeError) {
      // 忽略移除失败的错误，元素可能已经被移除
      console.warn('移除克隆元素时出错:', removeError);
    }

    // 设置缩略图的最终尺寸
    if (pngImage) {
      pngImage.width = width;
      pngImage.height = height;
    } else {
      throw new Error('生成的图片对象为空');
    }

    return pngImage;
  } catch (error) {
    console.error("生成缩略图失败:", error);
    throw error;
  }
}

/**
 * 确保元素内的所有资源（图片、视频等）都已加载完成
 * @param element 要检查的DOM元素
 * @returns Promise<void>
 */
async function ensureAllResourcesLoaded(element: HTMLElement): Promise<void> {
  const images = Array.from(element.querySelectorAll('img'));
  const videos = Array.from(element.querySelectorAll('video'));
  
  // 等待所有图片加载完成
  const imageLoadPromises = images.map(img => {
    if (img.complete) return Promise.resolve();
    return new Promise<void>((resolve, reject) => {
      img.onload = () => resolve();
      img.onerror = () => {
        console.warn(`图片加载失败: ${img.src}`);
        resolve(); // 继续执行，不中断流程
      };
      // 设置超时处理
      setTimeout(() => resolve(), 5000);
    });
  });
  
  // 等待所有视频加载第一帧
  const videoLoadPromises = videos.map(video => {
    return new Promise<void>((resolve) => {
      if (video.readyState >= 1) {
        resolve();
      } else {
        video.addEventListener('loadeddata', () => resolve(), { once: true });
        video.addEventListener('error', () => {
          console.warn(`视频加载失败: ${video.src}`);
          resolve(); // 继续执行，不中断流程
        });
        // 设置超时处理
        setTimeout(() => resolve(), 5000);
      }
    });
  });
  
  // 等待所有资源加载完成
  await Promise.all([...imageLoadPromises, ...videoLoadPromises]);
}

/**
 * 处理克隆元素中的特殊元素（canvas、video等）
 * @param clonedElement 克隆的DOM元素
 * @param originalElement 原始DOM元素
 * @returns Promise<void>
 */
async function processSpecialElements(
  clonedElement: HTMLElement,
  originalElement: HTMLElement
): Promise<void> {
  // 处理canvas元素
  const canvasElements = originalElement.querySelectorAll('canvas');
  const clonedCanvasElements = clonedElement.querySelectorAll('canvas');
  
  clonedCanvasElements.forEach((canvas, index) => {
    if (index < canvasElements.length) {
      const originalCanvas = canvasElements[index];
      const img = document.createElement('img');
      try {
        // 直接从原始canvas获取数据
        img.src = originalCanvas.toDataURL('image/png');
        canvas.replaceWith(img);
      } catch (error) {
        console.warn('处理canvas元素时出错:', error);
        // 出错时保留原始canvas
      }
    }
  });
  
  // 处理video元素
  const videoElements = originalElement.querySelectorAll('video');
  const clonedVideoElements = clonedElement.querySelectorAll('video');
  
  clonedVideoElements.forEach((video, index) => {
    if (index < videoElements.length) {
      const originalVideo = videoElements[index];
      const img = document.createElement('img');
      
      try {
        const canvas = document.createElement('canvas');
        // 使用视频的实际尺寸或合理默认值
        // canvas.width = originalVideo.videoWidth || 150;
        // canvas.height = originalVideo.videoHeight || 200;
        canvas.width = 150;
        canvas.height = 200;
        const ctx = canvas.getContext('2d');
        
        if (ctx && originalVideo.readyState >= 1) {
          ctx.drawImage(originalVideo, 0, 0, canvas.width, canvas.height);
          img.src = canvas.toDataURL('image/png');
          video.replaceWith(img);
        } else {
          // 如果无法绘制视频帧，使用占位图或保留原始视频
          console.warn('无法绘制视频帧，视频未准备好');
        }
      } catch (error) {
        console.warn('处理video元素时出错:', error);
        // 出错时保留原始video
      }
    }
  });
}

/**
 * 将缩略图转换为DataURL
 * @param thumbnail 缩略图元素
 * @returns string DataURL格式的图片数据
 */
export function thumbnailToDataURL(thumbnail: HTMLImageElement): string {
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");

  if (!ctx) {
    throw new Error("无法获取Canvas上下文");
  }

  canvas.width = thumbnail.width;
  canvas.height = thumbnail.height;

  // 将图片绘制到canvas上
  ctx.drawImage(thumbnail, 0, 0, canvas.width, canvas.height);

  // 转换为DataURL
  return canvas.toDataURL("image/png");
}

/**
 * 使用dom-to-image-more 生成缩略图
 * @param element 要生成缩略图的DOM元素
 * @param options 缩略图配置选项
 * @returns Promise<HTMLImageElement> 生成的缩略图图片元素
 */

export async function generateThumbnailByDomToImageMore(
  element: HTMLElement,
  options: ThumbnailOptions
): Promise<HTMLImageElement> {
  try {
    // 从选项中提取参数，设置默认值
    const { width, height, scale = 1, quality = 0.9 } = options;

    // 检查元素是否存在
    if (!element) {
      throw new Error("DOM元素不存在");
    }

    // 克隆原始元素，避免修改原始DOM
    const clonedElement = element.cloneNode(true) as HTMLElement;

    // 处理克隆元素中canvas元素
    const canvasElements = element.querySelectorAll("canvas");
    const clonedCanvasElements = clonedElement.querySelectorAll("canvas");
    clonedCanvasElements.forEach((canvas, index) => {
      const img = document.createElement("img");
      // 把画布内容转换成图片
      //   html2canvas(canvas).then((canvas) => {
      //     img.src = canvas.toDataURL("image/png");
      //   });
      const ctx = canvasElements[index].getContext("2d");
      ctx?.drawImage(
        canvasElements[index],
        0,
        0,
        canvasElements[index].width,
        canvasElements[index].height
      );
      img.src = canvasElements[index].toDataURL("image/png");
      canvas.replaceWith(img);
    });

    // 处理克隆元素中视频元素
    const videoElements = element.querySelectorAll("video");
    const clonedVideoElements = clonedElement.querySelectorAll("video");
    clonedVideoElements.forEach((video, index) => {
      //   把视频内容转换成图片
      const img = document.createElement("img");
    //   video.pause();
      //   html2canvas(video).then((canvas) => {
      //     img.src = canvas.toDataURL("image/png");
      //   });
      const canvas = document.createElement("canvas");
      canvas.width = 150;
      canvas.height = 200;
      const ctx = canvas.getContext("2d");
      ctx?.drawImage(
        videoElements[index],
        0,
        0,
        150,
        200
      );
      img.src = canvas.toDataURL("image/png");
      console.log("视频元素",150);
      video.replaceWith(img);
    });

    // 临时设置克隆元素的样式以适应缩略图尺寸
    // const originalStyle = {
    //   width: clonedElement.style.width,
    //   height: clonedElement.style.height,
    //   position: clonedElement.style.position,
    //   top: clonedElement.style.top,
    //   left: clonedElement.style.left,
    //   opacity: clonedElement.style.opacity,
    //   zIndex: clonedElement.style.zIndex,
    // };

    // 设置克隆元素的样式使其不可见但可以被渲染
    clonedElement.style.width = `${width / scale}px`;
    clonedElement.style.height = `${height / scale}px`;
    clonedElement.style.position = "absolute";
    clonedElement.style.top = "-9999px";
    clonedElement.style.left = "-9999px";
    // clonedElement.style.opacity = '0';
    clonedElement.style.zIndex = "-1";

    // 将克隆元素添加到文档中以便渲染
    document.body.appendChild(clonedElement);

    // 使用dom-to-image-more生成PNG图片DataURL
    const dataUrl = await domtoimage.toPng(clonedElement, {
      quality: quality,
      width: width / scale,
      height: height / scale,
      style: {
        transform: `scale(${scale})`,
        transformOrigin: "top left",
        width: `${width / scale}px`,
        height: `${height / scale}px`,
      },
    });

    // 恢复克隆元素的原始样式并从文档中移除
    // Object.assign(clonedElement.style, originalStyle);
    document.body.removeChild(clonedElement);

    // 创建图片元素并设置数据
    const pngImage = new Image();
    pngImage.src = dataUrl;

    // 设置缩略图的最终尺寸
    pngImage.width = width;
    pngImage.height = height;

    // 确保图片加载完成
    return new Promise((resolve, reject) => {
      pngImage.onload = () => resolve(pngImage);
      pngImage.onerror = reject;
    });
  } catch (error) {
    console.error("使用dom-to-image-more生成缩略图失败:", error);
    throw error;
  }
}